/*
 * Copyright (c) 2020-2021 Du Tian Wei
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import router from '@system.router';
import fileio from '@ohos.fileio';
import * as obvm from '../../common/runtime/vm.js';
import * as obcanvaslib from '../../common/canvas.js'
import featureAbility from '@ohos.ability.featureAbility'
import prompt from '@system.prompt';
import app from '@system.app';
import storage from '@system.storage';

let filepath = "/storage/emulated/0/Android/data/com.openblockhos.hmservice/files/Download/main.xe";
// https://github.com/uxitten/polyfill/blob/master/string.polyfill.js
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
if (!String.prototype.padStart) {
    String.prototype.padStart = function padStart(targetLength, padString) {
        targetLength = targetLength >> 0; //floor if number or convert non-number to 0;
        padString = String((typeof padString !== 'undefined' ? padString : ' '));
        if (this.length > targetLength) {
            return String(this);
        }
        else {
            targetLength = targetLength - this.length;
            if (targetLength > padString.length) {
                padString += padString.repeat(targetLength / padString.length); //append to original to ensure we are longer than needed
            }
            return padString.slice(0, targetLength) + String(this);
        }
    };
}
if (!Object.values) Object.values = function (obj) {
    if (obj !== Object(obj))
    throw new TypeError('Object.values called on a non-object');
    var val = [], key;
    for (key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            val.push(obj[key]);
        }
    }
    return val;
}

//function _base64ToArrayBuffer(base64) {
//    var binary_string = globalThis.ArrayBuffer(base64);
//    var len = binary_string.length;
//    var bytes = new Uint8Array(len);
//    for (var i = 0; i < len; i++) {
//        bytes[i] = binary_string.charCodeAt(i);
//    }
//    return bytes.buffer;
//}

let dwidth;
let loadedScript;
let canvas;

export default {
    data: {
        info: "info:",
        vm: null,
        fsm: null,
        uninited: true,
        updateInterval: 0,
        fileCheckInterval: 0,
        filectime: -1,
        ui: [{
                 type: 'button'
             }]
    },
    log(s) {
        console.log('OpenBlock ' + s);
        this.info += "\n" + s;
    },
    ob_event(name, argType, arg) {
        if (this.vm) {
            console.log(JSON.stringify({
                name, argType, arg
            }));
            this.vm.BroadcastMessage(new obvm.OBEventMessage(name, argType, arg, null));
        }
    },
    v2(e) {
        console.log(JSON.stringify(e));
        return {
            x: e.localX, y: e.localY
        };
    },
    touchstart(e) {
        this.ob_event('touchstart', 'Vector2', this.v2(e.touches[0]));
    },
    touchmove(e) {
        this.ob_event('touchmove', 'Vector2', this.v2(e.changedTouches[0]));
    },
    touchend(e) {
        this.ob_event('touchend', 'Vector2', this.v2(e.changedTouches[0]));
    },
    click(e) {
        this.ob_event('click', 'Vector2', this.v2(e));
    },
    async initStage() {
        console.log('aaaa');
        let want = await featureAbility.getWant();
        console.log('bbbbb');
        console.log(JSON.stringify(want));
        console.log(JSON.stringify(want.uri));
        console.log('cccc');
        //        let bytes = want.parameters.bytes;
        //        if (!bytes) {
        //            return;
        //        }

        let exFilePath = want.parameters.exFilePath;
        if (exFilePath) {
            filepath = exFilePath;
            storage.set({
                key: 'exFilePath'
            , value: exFilePath
            })
            this.asyncloadXe();
        } else {
            //            filepath = exFilePath;
            let that = this;
            storage.get({
                key: 'exFilePath',
                success: function (data) {
                    console.log('call storage.get success: ' + data);
                    filepath = data;
                    that.asyncloadXe();
                },
                fail: function (data, code) {
                    console.log('call storage.get fail, code: ' + code + ', data: ' + data);
                },
                complete: function () {
                    console.log('call complete');
                },
            });
        }
    },
    async asyncloadXe() {
        setTimeout(() => {
            this.loadXe();
        }, 5);
    },
    async loadXe() {
        //        var context = featureAbility.getContext();
        //        context.getFilesDir().then((dir) => {
        //            console.error("root dir=" + dir);
        let stage = this.$refs.canvas1;
        try {
            //                console.log('openblock 中文'+'测试');
            // /storage/media/100/local/files

            //                filepath = "/storage/emulated/0/Android/data/com.openblockhos.hmservice/files/Download/main.xe";//dir + "/main.xe";//"/data/"+app.getInfo().appID+"/main.xe";
            this.log(filepath);
            //                filepath =await context.getCacheDir();
            //                this.log(filepath);
            //                filepath = filepath + '/main.xe';
            //                stage.width = stage.width;
            //                this.log(filepath);
            this.log("000111");
            await fileio.access(filepath, 4);
            this.log(filepath);
            let st = fileio.statSync(filepath);
            this.log(111111111111);
            this.filectime = st.ctime;
            let fd = fileio.openSync(filepath, 0o2);
            this.log(22222222222222);
            let scriptArrayBuffer = new ArrayBuffer(st.size);
            this.log(3333333333333333333333);
            await fileio.read(fd, scriptArrayBuffer);
            //
            //                    this.log(4444444444444444444444444444);
            let obcanvas = new obcanvaslib.OBCanvas2D(stage);
            let canvas2dctx = obcanvas.canvas2dctx;
            canvas2dctx.restore();
            canvas2dctx.clearRect(0, 0, stage.width, stage.height);
            canvas2dctx.save();
            //            let ctx = stage.getContext('2d');
            //            ctx.fillRect(15, 15, 50, 50);

            let nativeLibs = [obcanvas.install.bind(obcanvas)];
            let loader = obvm.OBScriptLoader;
            let loadedScript = loader.loadScript(scriptArrayBuffer, nativeLibs);
            this.vm = new obvm.OBVM(loadedScript, {
                setTimeout: setTimeout, Output: this.log
            });
            //                // vm.Output = alert.bind(window);
            //            this.vm.Output = this.log;//prompt.showToast;
            let fsmname = 'Start.Main';
            let fsm = this.vm.CreateFSM(fsmname);
            if (!fsm) {
                this.log('no fsm');
                throw Error("No FSM named " + fsmname);
            }
            this.log(fsmname + ' created');
            this.fsm = fsm;

        } catch (e) {
            this.log("\nERROR:" + e.toString() + "\n" + JSON.stringify(e));
        } finally {
        }
        //        });
    },
    pageError(e) {
        this.log(e.message);
    },
    onActive() {
        console.log('========================================================================================');
        let that = this;

        setTimeout(() => {
            console.log("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" + this.uninited);
            if (that.uninited) {
                console.log("11111111111111111111111111111111111111111111111111");
                that.uninited = false;
                that.initStage();
            }
            //            this.updateInterval = setInterval(this.update, 5000);


            function step() {
                requestAnimationFrame(step);
                that.update();
            }

            requestAnimationFrame(step);
            console.log("start checking file");
            that.fileCheckInterval = setInterval(() => {
                that.checkFile();
            }, 10000);
        }, 1);
    },
    checkFile() {
        //        let fd = fileio.openSync(filepath, 0o2);
        console.log("checking" + filepath);
        let stat = fileio.statSync(filepath);
        let ctime = stat.ctime;
        console.log("stat " + JSON.stringify(stat) + " this.filectime " + this.filectime);
        //        fileio.closeSync(fd);
        if (this.filectime == -1) {
            this.filectime = ctime;
        } else if (this.filectime != ctime) {
            this.filectime = ctime;
            this.initStage();
        }
    },
    onInactive() {
        //        clearInterval(this.updateInterval);
        //        clearInterval(this.fileCheckInterval);
    },
    update() {
        if (this.info.length > 500) {
            this.info = this.info.substring(500);
        }
        //        console.log("update 1");
        try {
            if (this.vm) {
//                                console.log("update 2");
                this.vm.update();
//                                console.log("update 3");
            }
        } catch (e) {
            this.log("\nERROR:" + e.toString() + "\n" + JSON.stringify(e));
        }
    },
    onchange(type) {
        router.push({
            uri: "pages/" + type + "/index"
        })
    },
    onNewRequest() {
        this.initStage();
    }
}
